
/* <primitive: 80>
 * <ContextPart> blockCopy: argc <SmallInteger>
 * Answer a BlockContext.
 * Essential.
 */
void primBlockCopy()
{
	int ctxt, argc, newblock, initialPC, i; 
	
	ctxt = peek(1); //must be context
	argc = peek(0); //must be small int
				//else return nil
				
	if(!isSmInt(argc)) PANIC("argc not smint");
	
	newblock = instantiateN( BlockContext, 57 );
	
	saveContextRegisters();
	initialPC = unpackSmInt(slotOf(ctxt, 2)) + 2; //+2 to skip over the jump
	
	if( classOf(ctxt)==BlockContext ) ctxt = slotOf(ctxt,6); //home
	else if( classOf(ctxt)==MethodContext ) {}
	else {
		PANIC("not a context");
	}
		
	setSlotOf( newblock, 1, nil ); //sender
	setSlotOf( newblock, 2, packSmInt(initialPC) ); //pc
	setSlotOf( newblock, 3, argc ); //stackp
	setSlotOf( newblock, 4, argc ); //argc
	setSlotOf( newblock, 5, packSmInt(initialPC) ); //initial pc
	setSlotOf( newblock, 6, ctxt ); //home
	
	popNandPush(2, newblock);
}

/* <primitive: 81>
 * <BlockContext> value:* <Object>
 * Activate a BlockContext.
 * Essential.
 */
void primValue(int argc)
{
	int block, i;
	
	block = peek(argc);
	
	if( classOf(block) != BlockContext ) PANIC("not block context");
	
	if( unpackSmInt(slotOf(block, 4)) != argc ) PANIC("wrong argc");
	
	if( slotOf(block, 1) != nil ) PANIC("block already active");

	for(i=argc; i>0; i--)
	{
		setSlotOf( block, 6+i, pop() );
	}
	pop();//the block
	
	saveContextRegisters();
	
	setSlotOf( block, 1, activeContext ); //sender
	setSlotOf( block, 2, slotOf( block, 5 ) ); //pc
	setSlotOf( block, 3, packSmInt(argc) ); //sp
	
	loadContextRegistersFrom( block );
	
	//depth++;
	if(!success) PANIC("no success?");
}

/* <primitive: 82>
 * <BlockContext> valueWithArguments: <Array[Object]>
 * Activate a BlockContext.
 * Essential.
 */
void primValueWithArgs(int argc)
{
	int array, block, i;

	if(argc != 1) PANIC("should be 1");
	
	array = peek(0);
	block = peek(1);
	
	if( sizeOf(array) != unpackSmInt(slotOf(block, 4)) ){
		printf("%d should be %d\n", sizeOf(array), unpackSmInt(slotOf(block, 4)) );
		PANIC("incorrect arity");
	}
	
	if( slotOf(block, 1) != nil ) //sender notNil
		PANIC("block already active");
	
	argc = sizeOf(array);
	
	for(i=1; i<=argc; i++)
	{
		setSlotOf( block, 6+i, slotOf(array,i) );
	}
	
	pop(); //the array
	pop(); //the block
	
	saveContextRegisters();
	
	setSlotOf( block, 1, activeContext ); //sender
	setSlotOf( block, 2, slotOf( block, 5 ) ); //pc
	setSlotOf( block, 3, packSmInt(argc) ); //sp
	
	loadContextRegistersFrom( block );
}

/* <primitive: 83>
 * <Object> perform: Symbol with:* Object
 * 
 * Optional. (Image code will try again with the array version)
 */
void primPerform(int argc)
{
	success = 0; 
}

/* <primitive: 84>
 * <Object> perform: selector <Symbol> withArguments: argArray <Array>
 * 
 * Essential. (Squeak's version will try again with the super version, but ImplementationBase will not)
 */
void primPerformWithArgs()
{
	int newRcvr = peek(2);
	int selector = peek(1);
	int argArray = peek(0);
	int argArraySize = sizeOf(argArray);
	
	if( classOf(selector)!=Symbol ) PANIC("perform expects Symbol");
	if( classOf(argArray)!=Array ) PANIC("perform expects Array");
	
	popNandPush(argumentCount+1, newRcvr);
	
	for(int i=1; i<=argArraySize; i++)
		push( slotOf(argArray, i) );
		
	send( selector, argArraySize, 0 );
	success=1; //recursion can affect success flag
}
